package com.hx.voice.recognition.admin.rpc.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hx.voice.recognition.admin.constant.AdminCommonConstant;
import com.hx.voice.recognition.admin.manager.entity.Element;
import com.hx.voice.recognition.admin.manager.entity.Menu;
import com.hx.voice.recognition.admin.manager.entity.User;
import com.hx.voice.recognition.admin.manager.service.IElementService;
import com.hx.voice.recognition.admin.manager.service.IMenuService;
import com.hx.voice.recognition.admin.manager.service.IUserService;
import com.hx.voice.recognition.admin.vo.FrontUser;
import com.hx.voice.recognition.admin.vo.MenuTree;
import com.hx.voice.recognition.api.vo.authority.PermissionInfo;
import com.hx.voice.recognition.api.vo.user.UserInfo;
import com.hx.voice.recognition.auth.client.jwt.UserAuthUtil;
import com.hx.voice.recognition.common.constant.CommonConstants;
import com.hx.voice.recognition.common.util.TreeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @descripe：权限业务层
 * @company：南京华讯方舟通讯设备有限公司
 * @author：zhoujinbing
 * @time：2019/6/13 15:13
 * @version：V1.0
 */
@Service
public class PermissionService {

    @Autowired
    private IUserService userService;

    @Autowired
    private IMenuService iMenuService;

    @Autowired
    private IElementService iElementService;

    @Autowired
    private UserAuthUtil userAuthUtil;

    @Autowired
    private BCryptPasswordEncoder encoder;

    /**
    * @description 查询所有菜单
     * @method  getAllPermissionInfo
     * @param  []
     * @return java.util.List<com.hx.zjb.security.api.vo.authority.PermissionInfo>
     * @date: 2019/6/13 15:34
     * @author:zhoujinbing
     */
    public List<PermissionInfo> getAllPermissionInfo()
    {
        List<Menu> menus = iMenuService.selectMenuList();
        List<PermissionInfo> result = new ArrayList<>();
        menu2permission(menus,result);
        List<Element> elements = iElementService.selectElemetnList();
        element2permission(elements,result);
        return result;
    }

    /**
     * @description 菜单操作项元素转换成权限信息
     * @method  element2permission
     * @param  [elements, result]
     * @return void
     * @date: 2019/6/13 17:48
     * @author:zhoujinbing
     */
    private void element2permission(List<Element> elements, List<PermissionInfo> result) {
        PermissionInfo info;
        for (Element element : elements) {
            info = new PermissionInfo();
            info.setCode(element.getCode());
            info.setType(element.getType());
            info.setUri(element.getUri());
            info.setMethod(element.getMethod());
            info.setName(element.getName());
            info.setMenu(element.getMenuId());
            result.add(info);
        }
    }

    /**
     * @description 菜单转换成通用菜单权限
     * @method  menu2permission
     * @param  [menus, result]
     * @return void
     * @date: 2019/6/13 17:48
     * @author:zhoujinbing
     */
    private void menu2permission(List<Menu> menus, List<PermissionInfo> result) {
        PermissionInfo info;
        for (Menu menu : menus) {
            if(StrUtil.isBlank(menu.getHref()))
            {
                menu.setHref("/" + menu.getCode());
            }
            info = new PermissionInfo();
            info.setCode(menu.getCode());
            info.setType(AdminCommonConstant.RESOURCE_TYPE_MENU);
            info.setName(AdminCommonConstant.RESOURCE_ACTION_VISIT);
            String uri = menu.getHref();
            if(!uri.startsWith("/"))
            {
                uri = "/" + uri;
            }
            info.setUri(uri);
            info.setMethod(AdminCommonConstant.RESOURCE_REQUEST_METHOD_GET);
            info.setMenu(menu.getTitle());
            result.add(info);
        }

    }

    /**
     * @description 根据用户获取菜单以及操作动作
     * @method  getPermissionByUserName
     * @param  [username]
     * @return java.util.List<com.hx.zjb.security.api.vo.authority.PermissionInfo>
     * @date: 2019/6/14 14:33
     * @author:zhoujinbing
     */
    public List<PermissionInfo> getPermissionByUserName(String username) {
        User user = userService.getOne(new QueryWrapper<User>().eq("username", username));
        List<Menu> menus = iMenuService.getUserAuthorityMenuByUserId(user.getId());
        List<PermissionInfo> result = new ArrayList<>();
        menu2permission(menus,result);

        List<Element> elements = iElementService.getAuthrityElementByUserId(user.getId());
        element2permission(elements,result);
        return result;

    }

    /**
     * @description 校验用户，根据用户名密码校验
     * @method  validate
     * @param  [username, password]
     * @return com.hx.zjb.security.api.vo.user.UserInfo
     * @date: 2019/6/14 14:33
     * @author:zhoujinbing
     */
    public UserInfo validate(String username, String password) {
        UserInfo info = new UserInfo();
        User user = userService.getOne(new QueryWrapper<User>().eq("username", username));
        if(encoder.matches(password,user.getPassword()))
        {
            BeanUtil.copyProperties(user,info);
            info.setId(user.getId().toString());
        }
        return info;


    }

    /**
     * @description 根据token获取用户信息
     * @method  getUserInfo
     * @param  [token]
     * @return com.hx.zjb.security.admin.vo.FrontUser
     * @date: 2019/6/19 10:09
     * @author:zhoujinbing
     */
    public FrontUser getUserInfo(String token) throws Exception {
        String username = userAuthUtil.getInfoFormToken(token).getUniqueName();
        if(StrUtil.isEmpty(username))
        {
            return null;
        }

        User user = this.getUserByUsername(username);

        //封装前台用户信息
        FrontUser frontUser = new FrontUser();
        BeanUtil.copyProperties(user,frontUser);

        List<PermissionInfo> permissionByUserName = this.getPermissionByUserName(username);

        //根据用户名获取菜单
        Stream<PermissionInfo> menus = permissionByUserName.parallelStream().filter(permissionInfo -> {
            return permissionInfo.getType().equals(CommonConstants.RESOURCE_TYPE_MENU);
        });
        frontUser.setMenus(menus.collect(Collectors.toList()));

        //根据用户名获取操作按钮
        Stream<PermissionInfo> buttons = permissionByUserName.parallelStream().filter(permissionInfo -> {
            return !permissionInfo.getType().equals(CommonConstants.RESOURCE_TYPE_MENU);
        });
        frontUser.setElements(buttons.collect(Collectors.toList()));
        return frontUser;
    }

    private User getUserByUsername(String username)
    {
        return userService.getOne(new QueryWrapper<User>().eq("username",username));
    }

    /**
     * @description 根据用户权限获取用户所拥有的菜单
     * @method  getMenusByUsername
     * @param  [token]
     * @return java.util.List<com.hx.zjb.security.admin.vo.MenuTree>
     * @date: 2019/6/19 10:29
     * @author:zhoujinbing
     */
    public List<MenuTree> getMenusByUsername(String token) throws Exception {

        String uniqueName = userAuthUtil.getInfoFormToken(token).getUniqueName();
        if(StrUtil.isEmpty(uniqueName))
        {
            return null;
        }

        User user = this.getUserByUsername(uniqueName);
        List<Menu> userAuthorityMenuByUserId = iMenuService.getUserAuthorityMenuByUserId(user.getId());
        return getMenuTree(userAuthorityMenuByUserId,AdminCommonConstant.ROOT);


    }

    /**
     * @description 封装菜单树
     * @method  getMenuTree
     * @param  [userAuthorityMenuByUserId, root]
     * @return java.util.List<com.hx.zjb.security.admin.vo.MenuTree>
     * @date: 2019/6/19 10:33
     * @author:zhoujinbing
     */
    private List<MenuTree> getMenuTree(List<Menu> userAuthorityMenuByUserId, int root) {
        List<MenuTree> trees = new ArrayList<>();
        MenuTree node = null;
        for (Menu menu : userAuthorityMenuByUserId) {
            node = new MenuTree();
            BeanUtil.copyProperties(menu,node);
            trees.add(node);
        }
        return TreeUtil.build(trees,root);
    }
}